#include "order/MultinworkQuery.h"
#include "tools/Reader.h"
#include "tools/Diary.h"

ResdownLoad::ResdownLoad(QMap<ThreadPoint, NT::THREAD_STATE> &_impact_thread_) : runningState(false){
    request.setRawHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36 Edg/126.0.0.0");
    request.setRawHeader("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7");
    request.setRawHeader("accept-language", "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6");
    impact_thread = &_impact_thread_;
    (*impact_thread)[ThreadPoint::NETWORK_VISIT] = NT::THREAD_RECOVER;
}

QMap<QString, QString> ResdownLoad::getrawHeader(QString url){
    request.setUrl(url);
    if (!request.url().isValid()) setProperty("request-package", "url is unvalid");
    QNetworkReply *reply = nullptr;
    QNetworkAccessManager manager;
    reply = manager.head(request);
    QEventLoop loop;
    connect(reply, &QNetworkReply::finished, &loop, &QEventLoop::quit);
    loop.exec();
    QList<QNetworkReply::RawHeaderPair> headinfo = reply->rawHeaderPairs();
    QMap<QString, QString> infostruct;
    foreach(auto i, headinfo)
    {
        infostruct.insert(i.first, i.second);
    }
    return infostruct;
}

void ResdownLoad::start(QString lockey){
    runningKey.swap(lockey);
    run();
}

void ResdownLoad::run(){
    QMutex lock;
    lock.lock();
    runningState = true;
    (*impact_thread)[ThreadPoint::NETWORK_VISIT] = NT::THREAD_RECOVER;
    QList<QVariant> address = infomap[runningKey]["address"];
    QList<QVariant> incast = infomap[runningKey]["address-incast"];
    QList<QVariant> multivars = infomap[runningKey]["multiargs"];
    QList<QVariant> downFlags = infomap[runningKey]["downFlags"];
    QList<QVariant> webdatas;
    int index = 0;
    while (index < address.size())
    {
        QString urc = address[index].toString(); QUrl url(urc);
        if ((*impact_thread)[ThreadPoint::NETWORK_VISIT] == NT::THREAD_TERMINATED)
        {
            break;
        }
        else if ((*impact_thread)[ThreadPoint::NETWORK_VISIT] == NT::THREAD_PAUSE)
        {
            while (true)
            {
                if ((*impact_thread)[ThreadPoint::NETWORK_VISIT] == NT::THREAD_PAUSE)
                {
                    QThread::msleep(15);
                    continue;
                }
                else
                {
                    break;
                }
            }
        }
        else
        {

            if (infomapState[urc])
            {
                continue;
            }
            else
            {
                QMap<QString, QString> headinfo = getrawHeader(urc);
                request.setRawHeader("Content-Type", headinfo["Content-Type"].toLocal8Bit());
                request.setRawHeader("Set-Cookie", headinfo["Set-Cookie"].toLocal8Bit());
                ulong rsize = headinfo["Content-Length"].toULong();
                diary("get response content type: " + headinfo["Content-Type"], Diary::Warning)
                QUrlQuery query;
                if(index < incast.size()) parserIncast(query, incast[index]);
                if (!query.isEmpty()) url.setQuery(query);
                request.setUrl(url);
                if (!request.url().isValid()) diary("url is unvalid", Diary::Error);
                QNetworkAccessManager manager;
                QNetworkReply *reply = nullptr;
                QVariant multivar;
                QVariant downFlagvar;
                (index >= multivars.size()) ? multivar = "" : multivar = multivars[index];
                (index >= downFlags.size()) ? downFlagvar = downFlags[0] : downFlagvar = downFlags[index];
                DLFLAG downFlag = downFlagvar.value<DLFLAG>();
                if (GETFLAG.contains(downFlag))
                {
                    reply = manager.get(request);
                }
                else if (PUTFLAG.contains(downFlag))
                {
                    reply = manager.put(request, multivar.toByteArray());
                }
                else if (POSTFLAG.contains(downFlag))
                {
                    reply = manager.post(request, multivar.toByteArray());
                }
                if (rsize && VARIANTFLAG.contains(downFlag)) emit request_process_exdwings(false);
                if (VARIANTFLAG.contains(downFlag)) connect(reply, &QNetworkReply::downloadProgress, this, &ResdownLoad::request_process);
                if (reply)
                {
                    diary("get reply sucess,map url ->" + urc, Diary::Debug)
                    QEventLoop loop;
                    connect(reply, &QNetworkReply::finished, &loop, &QEventLoop::quit);
                    loop.exec();
                    QByteArray webpage;
                    if (reply->error() == QNetworkReply::NoError)
                    {
                        if (GETFLAG.contains(downFlag))
                        {
                            webpage = reply->readAll();
                            webdatas.append(QVariant(webpage));
                        }

                        else if (PUTFLAG.contains(downFlag))
                        {
                            webpage = reply->readAll();
                            webdatas.append(QVariant(webpage));
                        }

                        else if (POSTFLAG.contains(downFlag))
                        {
                            webpage = reply->readAll();
                            webdatas.append(QVariant(webpage));
                        }
                        QString urlpath = multivar.toString();
                        SCROPED_PATH_MAKE(urlpath)
                        if (QFile(urlpath).exists() && urlpath.size() > 3)
                        {
                            Reader::d_writer(urlpath, webpage);
                            diary2("source save sucess,map url ->", urc, Diary::Debug)
                        }
                        infomapState[urc] = true;
                    }
                    else
                    {
                        diary(reply->errorString() + ",map url ->" + urc, Diary::Error)
                        infomapState[urc] = false;
                    }
                } else diary("get reply fail,map url ->" + urc, Diary::Error)
                if (rsize && VARIANTFLAG.contains(downFlag)) emit request_process_exdwings(true);
                reply = nullptr;
            }
            QThread::msleep(40);
        }
        QVariant historyVariant = property(runningKey.toStdString().data());
        if (!historyVariant.isNull())
        {
            foreach(QVariant var, historyVariant.toList())
            {
                webdatas.append(var.toByteArray());
            }
        }
        index++;
    }
    setProperty(runningKey.toStdString().data(), webdatas);
    lock.unlock();
    runningState = false;
    emit finished();
    (*impact_thread)[ThreadPoint::NETWORK_VISIT] = NT::THREAD_IDLEABOUT;
}

QList<QVariant> ResdownLoad::captrueData(QString lockey){
    if (runningState)
    {
        QEventLoop loop;
        connect(this, &ResdownLoad::finished, &loop, &QEventLoop::quit);
        loop.exec();
    }
    QList<QVariant> webdata = property(lockey.toStdString().data()).toList();
    setProperty(lockey.toStdString().data(), QVariant());
    infomapState.clear();
    return webdata;
}

void ResdownLoad::captrueData(QString lockey, QList<QVariant> &data){
    QList<QVariant> byte = captrueData(lockey);
    if (!byte.isEmpty()) data.swap(byte);
}

void ResdownLoad::captrueData(QString lockey, QVariant &data){
    QList<QVariant> byte = captrueData(lockey);
    if (!byte.isEmpty()) data = byte.first();
}

QJsonDocument ResdownLoad::jsparser(QByteArray data){
    return QJsonDocument::fromJson(data);
}

void ResdownLoad::parserIncast(QUrlQuery &g, QVariant data){
    if (data.metaType().id()  == QMetaType::QVariantMap)
    {
        QMap<QString, QVariant> dattm = data.toMap();
        QList<QString> likeys = dattm.keys();
        QList<QVariant> livalues = dattm.values();
        for(int index=0; index < dattm.size(); index++)
        {
            g.addQueryItem(likeys[index], livalues[index].toString());

        }
    }
    else if (QList<QMetaType::Type>({QMetaType::QStringList, QMetaType::QVariantList}).contains(data.metaType().id()))
    {
        QList<QVariant> varlis;
        varlis.append(data.toList());
        QString k = "";
        QString v = "";
        for(int index=0; index < varlis.size(); index++)
        {
            if ((index + 1) % 2 == 0)
            {
                v = varlis[index].toString();
                g.addQueryItem(k, v);
            }
            else
            {
                k = varlis[index].toString();
            }
        }
    }
    else
    {
        QJsonObject jsobj;
        QJsonDocument doc = data.value<QJsonDocument>();
        if (doc.isEmpty())
        {
            jsobj = data.value<QJsonObject>();
        }
        else
        {
            jsobj = doc.object();
        }
        if (!jsobj.isEmpty())
        {
            QList<QString> likeys = jsobj.keys();
            foreach(QString key, likeys)
            {
                QJsonValue v = jsobj.value(key);
                QString value = "";
                if (v.type() == QJsonValue::Bool)
                {
                    value = value.number(v.toBool());
                }
                else if (v.type() == QJsonValue::Double)
                {
                    value = value.number(v.toDouble());
                }
                else if (v.type() == QJsonValue::String)
                {
                    value = v.toString();
                }
                else if (v.type() == QJsonValue::Array)
                {
                    value = QVariant::fromValue(v).toString();
                }
                g.addQueryItem(key, value);
            }
        }
    }
}
